<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HTTP-FLV 视频流播放器</title>
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/flv.js@1.6.2/dist/flv.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Roboto', sans-serif;
            background: linear-gradient(135deg, #0f2027, #203a43, #2c5364);
            color: #fff;
            min-height: 100vh;
            padding: 20px;
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .container {
            max-width: 1200px;
            width: 100%;
            background: rgba(0, 0, 0, 0.7);
            border-radius: 15px;
            padding: 30px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
            margin-top: 20px;
        }

        header {
            text-align: center;
            margin-bottom: 30px;
            padding-bottom: 20px;
            border-bottom: 1px solid rgba(255, 255, 255, 0.1);
        }

        h1 {
            font-size: 2.8rem;
            margin-bottom: 10px;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
            background: linear-gradient(to right, #00c9ff, #92fe9d);
            -webkit-background-clip: text;
            background-clip: text;
            color: transparent;
        }

        .subtitle {
            font-size: 1.2rem;
            opacity: 0.9;
            margin-bottom: 20px;
        }

        .player-container {
            position: relative;
            width: 100%;
            padding-top: 56.25%; /* 16:9 Aspect Ratio */
            background-color: #000;
            border-radius: 10px;
            overflow: hidden;
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
            margin-bottom: 30px;
        }

        #video-player {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            outline: none;
        }

        .controls {
            display: flex;
            justify-content: space-between;
            margin-bottom: 25px;
            gap: 15px;
            flex-wrap: wrap;
        }

        .url-input {
            flex-grow: 1;
            padding: 14px 20px;
            border: none;
            border-radius: 50px;
            font-size: 1.1rem;
            background: rgba(255, 255, 255, 0.1);
            color: white;
            outline: none;
            transition: background 0.3s;
        }

        .url-input:focus {
            background: rgba(255, 255, 255, 0.15);
        }

        .btn {
            padding: 14px 30px;
            border: none;
            border-radius: 50px;
            background: linear-gradient(to right, #00c9ff, #92fe9d);
            color: #222;
            font-size: 1.1rem;
            font-weight: 500;
            cursor: pointer;
            transition: transform 0.2s, box-shadow 0.2s;
            box-shadow: 0 4px 15px rgba(0, 201, 255, 0.4);
        }

        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 20px rgba(0, 201, 255, 0.6);
        }

        .btn:active {
            transform: translateY(1px);
        }

        .stats-container {
            display: flex;
            justify-content: space-around;
            flex-wrap: wrap;
            gap: 20px;
            margin-bottom: 30px;
        }

        .stat-card {
            flex: 1;
            min-width: 200px;
            background: rgba(0, 0, 0, 0.4);
            border-radius: 10px;
            padding: 20px;
            text-align: center;
        }

        .stat-title {
            font-size: 1.2rem;
            margin-bottom: 10px;
            color: #00c9ff;
        }

        .stat-value {
            font-size: 1.8rem;
            font-weight: 700;
        }

        .info-section {
            display: flex;
            flex-wrap: wrap;
            gap: 30px;
            margin-top: 20px;
        }

        .info-card {
            flex: 1;
            min-width: 300px;
            background: rgba(0, 0, 0, 0.4);
            border-radius: 10px;
            padding: 25px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
        }

        .info-card h2 {
            font-size: 1.5rem;
            margin-bottom: 15px;
            color: #92fe9d;
        }

        .info-card p {
            line-height: 1.7;
            margin-bottom: 15px;
        }

        .status {
            font-weight: bold;
            color: #4caf50;
        }

        .features {
            padding: 0;
            margin-left: 20px;
        }

        .features li {
            margin-bottom: 10px;
            display: flex;
            align-items: center;
        }

        .features li:before {
            content: "✓";
            color: #4caf50;
            font-weight: bold;
            margin-right: 10px;
        }

        .server-details {
            margin-top: 30px;
            text-align: center;
            font-size: 1.1rem;
            opacity: 0.9;
        }

        .code {
            font-family: monospace;
            background: rgba(0, 0, 0, 0.4);
            padding: 3px 8px;
            border-radius: 4px;
        }

        footer {
            text-align: center;
            margin-top: 40px;
            padding-top: 20px;
            border-top: 1px solid rgba(255, 255, 255, 0.1);
            width: 100%;
            opacity: 0.8;
        }

        @media (max-width: 768px) {
            .container {
                padding: 15px;
            }

            h1 {
                font-size: 2.2rem;
            }

            .controls {
                flex-direction: column;
            }

            .btn {
                width: 100%;
            }

            .stats-container {
                flex-direction: column;
            }
        }
    </style>
</head>
<body>
<div class="container">
    <header>
        <h1>HTTP-FLV 视频流播放器</h1>
        <p class="subtitle">基于您的自定义HTTP-FLV服务器实现低延迟流媒体播放</p>
    </header>

    <div class="player-container">
        <video id="video-player" controls></video>
    </div>

    <div class="controls">
        <input
                type="text"
                class="url-input"
                id="stream-url"
                value="http://127.0.0.1:8080/input.flv"
                placeholder="输入HTTP-FLV流URL..."
        >
        <button class="btn" id="play-btn">播放视频流</button>
    </div>

    <div class="stats-container">
        <div class="stat-card">
            <div class="stat-title">延迟</div>
            <div class="stat-value"><span id="latency-value">0</span> ms</div>
        </div>
        <div class="stat-card">
            <div class="stat-title">缓冲区</div>
            <div class="stat-value"><span id="buffer-value">0</span> KB</div>
        </div>
        <div class="stat-card">
            <div class="stat-title">状态</div>
            <div class="stat-value"><span id="status-value">未连接</span></div>
        </div>
        <div class="stat-card">
            <div class="stat-title">传输速率</div>
            <div class="stat-value"><span id="speed-value">0</span> KB/s</div>
        </div>
    </div>

    <div class="info-section">
        <div class="info-card">
            <h2>关于HTTP-FLV</h2>
            <p>HTTP-FLV是一种基于HTTP协议的流媒体传输格式，它将FLV封装在HTTP协议中传输。</p>
            <p>相比传统的RTMP协议，HTTP-FLV具有更低的延迟（通常在1-3秒）和更好的防火墙穿透能力。</p>
            <p>播放器状态: <span id="player-status" class="status">等待播放指令</span></p>
        </div>

        <div class="info-card">
            <h2>技术优势</h2>
            <ul class="features">
                <li>超低延迟（1-3秒）</li>
                <li>无需浏览器插件</li>
                <li>基于HTTP协议，防火墙友好</li>
                <li>支持HTML5视频播放</li>
                <li>支持硬解码加速</li>
                <li>适用于直播和点播场景</li>
            </ul>
        </div>
    </div>

    <div class="server-details">
        <p>您的HTTP-FLV服务器运行在: <span class="code">http://127.0.0.1:8080/input.flv</span></p>
        <p>使用 <span class="code">ffplay http://127.0.0.1:8080/input.flv</span> 测试播放</p>
    </div>
</div>

<footer>
    <p>HTTP-FLV 视频流播放器 | 与您的HTTP-FLV服务器兼容</p>
</footer>

<script>
    document.addEventListener('DOMContentLoaded', function() {
        const video = document.getElementById('video-player');
        const playBtn = document.getElementById('play-btn');
        const urlInput = document.getElementById('stream-url');
        const statusText = document.getElementById('player-status');
        const latencyValue = document.getElementById('latency-value');
        const bufferValue = document.getElementById('buffer-value');
        const statusValue = document.getElementById('status-value');
        const speedValue = document.getElementById('speed-value');

        let flvPlayer = null;
        let bytesReceived = 0;
        let lastBytes = 0;
        let lastTime = Date.now();

        function initPlayer(url) {
            if (flvPlayer) {
                flvPlayer.destroy();
                flvPlayer = null;
            }

            if (flvjs.isSupported()) {
                flvPlayer = flvjs.createPlayer({
                    type: 'flv',
                    url: url,
                    isLive: true
                });

                flvPlayer.attachMediaElement(video);
                flvPlayer.load();

                statusText.textContent = "正在连接视频流...";
                statusValue.textContent = "连接中";

                flvPlayer.on(flvjs.Events.MEDIA_INFO, function(info) {
                    console.log('Media info:', info);
                    statusText.textContent = "已加载媒体信息，准备播放";
                    statusValue.textContent = "准备播放";
                });

                flvPlayer.on(flvjs.Events.STATISTICS_INFO, function(info) {
                    // 更新延迟信息
                    const latency = Math.round(info.downloadLatency);
                    latencyValue.textContent = latency;

                    // 更新缓冲区信息
                    const buffer = Math.round(video.buffered.length > 0 ?
                        video.buffered.end(0) - video.currentTime : 0);
                    bufferValue.textContent = buffer;

                    // 更新传输速率
                    const now = Date.now();
                    const duration = (now - lastTime) / 1000; // 转换为秒
                    const bytesDiff = bytesReceived - lastBytes;
                    const speed = duration > 0 ? Math.round(bytesDiff / duration / 1024) : 0;

                    speedValue.textContent = speed;

                    lastBytes = bytesReceived;
                    lastTime = now;
                });

                flvPlayer.on(flvjs.Events.ERROR, function(errorType, errorDetail, errorInfo) {
                    console.error('FLV Error:', errorType, errorDetail, errorInfo);
                    statusText.textContent = `错误: ${errorType} - ${errorDetail}`;
                    statusValue.textContent = "错误";
                });

                flvPlayer.on(flvjs.Events.LOADING_COMPLETE, function() {
                    statusText.textContent = "视频流加载完成";
                    statusValue.textContent = "加载完成";
                });

                flvPlayer.on(flvjs.Events.METADATA_ARRIVED, function() {
                    statusText.textContent = "接收到媒体元数据";
                });

                // 开始播放
                flvPlayer.play().then(() => {
                    statusText.textContent = "视频流播放中";
                    statusValue.textContent = "播放中";
                }).catch(err => {
                    console.error('播放失败:', err);
                    statusText.textContent = "播放失败: " + err.message;
                    statusValue.textContent = "播放失败";
                });
            } else {
                statusText.textContent = "错误：您的浏览器不支持HTTP-FLV播放";
                statusValue.textContent = "不支持";
            }
        }

        // 更新传输字节数
        const originalSend = XMLHttpRequest.prototype.send;
        XMLHttpRequest.prototype.send = function(body) {
            const xhr = this;
            const oldOnProgress = xhr.onprogress;

            xhr.onprogress = function(e) {
                bytesReceived = e.loaded;
                if (oldOnProgress) oldOnProgress.call(xhr, e);
            };

            originalSend.call(this, body);
        };

        playBtn.addEventListener('click', function() {
            const streamUrl = urlInput.value.trim();
            if (streamUrl) {
                initPlayer(streamUrl);
            } else {
                alert('请输入有效的HTTP-FLV流URL');
            }
        });

        // 初始加载默认流
        initPlayer(urlInput.value);

        // 添加键盘快捷键支持
        document.addEventListener('keydown', function(e) {
            if (e.key === ' ') {
                if (video.paused) {
                    video.play();
                } else {
                    video.pause();
                }
                e.preventDefault();
            } else if (e.key === 'ArrowRight') {
                video.currentTime += 5;
            } else if (e.key === 'ArrowLeft') {
                video.currentTime -= 5;
            } else if (e.key === 'f' || e.key === 'F') {
                if (video.requestFullscreen) {
                    video.requestFullscreen();
                } else if (video.mozRequestFullScreen) {
                    video.mozRequestFullScreen();
                } else if (video.webkitRequestFullscreen) {
                    video.webkitRequestFullscreen();
                } else if (video.msRequestFullscreen) {
                    video.msRequestFullscreen();
                }
            }
        });
    });
</script>
</body>
</html>